package com.xinggq.pay.service.service.impl;

import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinggq.pay.service.context.AppIdContext;
import com.xinggq.pay.service.pay.channel.yse.other.division.dto.DivisionParamDTO;
import com.xinggq.pay.service.dto.YsePayNotifyDTO;
import com.xinggq.pay.service.entity.PayCallbackEntity;
import com.xinggq.pay.service.entity.PayOrderEntity;
import com.xinggq.pay.service.enums.CallbackStatusEnum;
import com.xinggq.pay.service.enums.PayChannelEnum;
import com.xinggq.pay.service.pay.channel.yse.other.division.YseDivisionServiceImpl;
import com.xinggq.pay.service.service.AppCallbackService;
import com.xinggq.pay.service.service.ChannelCallbackService;
import com.xinggq.pay.service.service.PayOrderService;
import com.xinggq.pay.service.service.YseCallbackService;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @Description
 * @Author xinggq
 * @Date 2025/9/16
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class YseCallbackServiceImpl implements YseCallbackService {


  private static final String SUCCESS = "success";
  private static final String YSE_SUCCESS = "TRADE_SUCCESS";
  private static final String FAIL = "fail";


  private final ChannelCallbackService channelCallbackService;
  private final PayOrderService payOrderService;
  private final AppCallbackService appCallbackService;
  private final YseDivisionServiceImpl divisionService;

  @Override
  public String processYsePayCallback(String ysePayNotifyStr) {
    String channelTradeNo = null;
    try {
      YsePayNotifyDTO ysePayNotify = convertFromUrlParam(ysePayNotifyStr, YsePayNotifyDTO.class);
      PayCallbackEntity entity = buildCallbackEntity(ysePayNotify.getOutTradeNo(),
          convertToJsonStrFromUrlParam(ysePayNotifyStr));
      channelTradeNo = entity.getChannelTradeNo();
      if (channelCallbackService.save(entity)) {
        log.info("保存银盛支付回调记录成功，渠道订单号：{}", channelTradeNo);
        // 检查支付状态，如果成功则更新订单状态
        if (YSE_SUCCESS.equals(ysePayNotify.getTradeStatus())) {
          updatePayOrderStatus(entity.getTradeNo());
          // 异步执行应用回调，不影响银盛回调信息的保存
          appCallbackService.asyncExecuteCallback(entity.getTradeNo());
          // 异步执行分账登记，不影响银盛回调信息的保存
          divisionService.divisionAsync(
              new DivisionParamDTO(channelTradeNo, new BigDecimal(ysePayNotify.getTotalAmount())));
        }
        return SUCCESS;
      }
      saveFailCallbackRecord(channelTradeNo, ysePayNotifyStr, "保存回调记录失败");
      return FAIL;
    } catch (Exception e) {
      log.error("处理银盛支付回调异常，渠道订单号：{}", channelTradeNo, e);
      saveFailCallbackRecord(channelTradeNo, ysePayNotifyStr, "处理回调异常: " + e.getMessage());
      return FAIL;
    }
  }

  @Override
  public String processYseRefundCallback(String yseRefundNotifyStr) {
    String channelTradeNo = null;
    try {
      YsePayNotifyDTO yseRefundNotify = convertFromUrlParam(yseRefundNotifyStr,
          YsePayNotifyDTO.class);
      PayCallbackEntity entity = buildCallbackEntity(yseRefundNotify.getOutTradeNo(),
          convertToJsonStrFromUrlParam(yseRefundNotifyStr));
      channelTradeNo = entity.getChannelTradeNo();
      if (channelCallbackService.save(entity)) {
        log.info("保存银盛退款回调记录成功，渠道订单号：{}", channelTradeNo);
        // 检查退款状态，如果成功则触发应用回调
        if (YSE_SUCCESS.equals(yseRefundNotify.getTradeStatus())) {
          updatePayOrderStatus(entity.getTradeNo());
          // 异步执行应用回调，不影响银盛回调信息的保存
          appCallbackService.asyncExecuteCallback(entity.getTradeNo());
        }
        return SUCCESS;
      }
      saveFailCallbackRecord(channelTradeNo, yseRefundNotifyStr, "保存退款回调记录失败");
      return FAIL;
    } catch (Exception e) {
      log.error("处理银盛退款回调异常，渠道订单号：{}", channelTradeNo, e);
      saveFailCallbackRecord(channelTradeNo, yseRefundNotifyStr,
          "处理退款回调异常: " + e.getMessage());
      return FAIL;
    }
  }

  /**
   * 将URL参数转换为指定对象
   * @param urlParams
   * @param clazz
   * @return
   * @param <T>
   */
  private <T> T convertFromUrlParam(String urlParams, Class<T> clazz) {
    // 1. 解码URL参数
    String decodedParams = URLDecoder.decode(urlParams, StandardCharsets.UTF_8);
    // 2. 转换为Map
    Map<String, Object> paramsMap = parseParamsToMap(decodedParams);
    JSONObject jsonObject = new JSONObject(paramsMap);
    // 3. 转换为目标对象（下划线自动转驼峰）
    return JSON.parseObject(jsonObject.toString(), clazz);
  }

  /**
   * 将URL参数转换为指定对象
   * @param urlParams
   */
  private String convertToJsonStrFromUrlParam(String urlParams) {
    // 1. 解码URL参数
    String decodedParams = URLDecoder.decode(urlParams, StandardCharsets.UTF_8);
    // 2. 转换为Map
    Map<String, Object> paramsMap = parseParamsToMap(decodedParams);
    JSONObject jsonObject = new JSONObject(paramsMap);
    // 3. 转换为目标对象（下划线自动转驼峰）
    return jsonObject.toJSONString();
  }


  /**
   * 构建回调记录实体
   */
  private PayCallbackEntity buildCallbackEntity(String channelTradeNo, String callbackData) {
    PayCallbackEntity entity = new PayCallbackEntity();
    PayOrderEntity payOrder = payOrderService.findByChannelTradeNoAndChannelType(channelTradeNo,
        PayChannelEnum.YSE);
    Validator.validateNotNull(payOrder, "未查询到对应订单信息，channelTradeNo:{}" + channelTradeNo);
    // 回调接口没有上下文信息，需要补全
    AppIdContext.setAppId(payOrder.getAppId());
    entity.setAppId(payOrder.getAppId());
    entity.setTradeNo(payOrder.getTradeNo());
    entity.setMerchantTradeNo(payOrder.getMerchantOrderNo());
    entity.setChannelTradeNo(channelTradeNo);
    entity.setChannelType(PayChannelEnum.YSE.getCode());
    entity.setCallbackData(callbackData);
    entity.setCallbackStatus(CallbackStatusEnum.SUCCESS.getCode());
    return entity;
  }

  /**
   * 更新支付订单状态
   */
  private void updatePayOrderStatus(String tradeNo) {
    PayOrderEntity payOrder = payOrderService.findByTradeNo(tradeNo);
    Validator.validateNotNull(payOrder, "未查询到响应订单信息，tradeNo:{}" + tradeNo);
    payOrder.setPayState(1);
    payOrder.setCompleteTime(LocalDateTime.now());
    payOrderService.updateById(payOrder);
  }

  /**
   * 保存失败的回调记录
   */
  private void saveFailCallbackRecord(String channelTradeNo, String callbackData, String errorMsg) {
    try {
      PayCallbackEntity entity = buildCallbackEntity(channelTradeNo, callbackData);
      entity.setCallbackStatus(CallbackStatusEnum.FAIL.getCode());
      // 截取错误信息，数据库字段长度为varchar(500)
      String truncatedErrorMsg = errorMsg;
      if (errorMsg != null && errorMsg.length() > 500) {
        truncatedErrorMsg = errorMsg.substring(0, 500);
      }
      entity.setErrorMsg(truncatedErrorMsg);
      channelCallbackService.save(entity);
    } catch (Exception e) {
      log.error("无法保存回调失败记录，渠道订单号：{}，原始数据：{}，失败原因：{}",
          channelTradeNo, callbackData, errorMsg, e);
    }
  }

  /**
   * 解析URL参数为Map
   */
  private static Map<String, Object> parseParamsToMap(String params) {
    Map<String, Object> map = new HashMap<>();
    if (params == null || params.isEmpty()) {
      return map;
    }

    String[] pairs = params.split("&");
    for (String pair : pairs) {
      String[] keyValue = pair.split("=", 2);
      String key = keyValue[0];
      String value = keyValue.length > 1 ? keyValue[1] : "";
      map.put(key, value);
    }
    return map;
  }


}
